/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.flexengine.component;

import com.flexengine.input.InputManager;
import com.flexengine.utils.FontManager;
import com.flexengine.view.Graphics;
import com.flexengine.view.Texture;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.font.FontRenderContext;
import java.util.ArrayList;
import java.util.EventListener;

/**
 * @author Luann R. Athayde
 * @version 1.0
 * @since 1.0
 */
public class Button extends GameComponent implements HorizontalTextAlign {
    
    private volatile String  label;
    private volatile Font    font;
    private volatile Color   foregroundColor;
    private volatile Color   foregroundFocusColor;
    
    private volatile Texture icon;
    
    private volatile Color   backgroundColor;
    private volatile Color   backgroundFocusColor;
    private volatile Color   borderColor;
    private volatile float   borderSize;
    
    private volatile int     roundRectWidth;
    private volatile int     roundRectHeight;
    
    private volatile float   transparence;
    
    private volatile int     horizontalTextAlign;
    
    private volatile ArrayList<EventListener> listeners;
    
    private volatile FontRenderContext fontContext;
    
    private volatile int     roundRect;
    
    private volatile boolean enable;
    
    public static final int ROUND_RECT_ALL     = 0;
    public static final int ROUND_RECT_NONE    = -1;
    public static final int ROUND_RECT_LEFT    = -10;
    public static final int ROUND_RECT_RIGHT   = -20;
    public static final int ROUND_RECT_TOP     = -30;
    public static final int ROUND_RECT_BOTTOM  = -40;

    public Button() {
        this("");
    }

    public Button(String label) {
        super("Button");
        this.label = label;
        this.font = FontManager.getFont(FontManager.defaultFont, 0, 12);
        // --
        this.basicBackgroundColor = this.backgroundColor = Color.BLACK;
        this.backgroundFocusColor = Color.LIGHT_GRAY;
        // --
        this.basicForegroundColor = this.foregroundColor = Color.WHITE;
        this.foregroundFocusColor = Color.DARK_GRAY;
        // --
        this.borderColor = BASIC_BORDER_COLOR;
        this.borderSize = 0;
        this.roundRectWidth = 0;
        this.roundRectHeight = 0;
        this.transparence = 1f;
        this.size = new Dimension(100, 20);
        this.horizontalTextAlign = HORIZONTAL_ALIGN_CENTER;
        this.listeners = new ArrayList<>();
        this.fontContext = new FontRenderContext(null, true, false);
        // --
        this.enable = true;
        this.icon = null;
        // --
        this.roundRect = ROUND_RECT_ALL;
    }

    @Override
    public void setSize(double width, double height) {
        super.setSize(width, height);
        if( size!=null && size.height>0 ) {
            roundRectWidth = roundRectHeight = size.height;
            font = FontManager.getFont("Arial", 0, (12*size.height)/20);
        }
    }

    @Override
    public void setSize(Dimension size) {
        super.setSize(size);
        if( size!=null && size.height>0 ) {
            roundRectWidth = roundRectHeight = size.height;
            font = FontManager.getFont("Arial", 0, (12*size.height)/20);
        }
    }

    private volatile int     mouseX, mouseY;
    private volatile boolean onFocus;
    private volatile Color   basicBackgroundColor;
    private volatile Color   basicForegroundColor;
    private volatile int     eventID = 0;
    @Override
    public void update(Long time, Long totalTime) {
        super.update(time,totalTime);
        mouseX = InputManager.getMouseX();
        mouseY = InputManager.getMouseY();
        if( enable && visible ) {
            if( mouseX>x && mouseX<x+size.width && mouseY>y && mouseY<y+size.height ) {
                onFocus = true;
                backgroundColor = backgroundFocusColor;
                foregroundColor = foregroundFocusColor;
            } else {
                onFocus = false;
                backgroundColor = basicBackgroundColor;
                foregroundColor = basicForegroundColor;
            }
        }
        if( onFocus && enable && visible && InputManager.isMouseCliked(InputManager.MOUSE_BUTTON1) ) {
            InputManager.releaseMouse(InputManager.MOUSE_BUTTON1);
            for(int i=0;i<listeners.size();i++) {
                EventListener tmp = listeners.get(i);
                if( tmp instanceof ActionListener ) {
                    ActionListener aEvent = (ActionListener)tmp;
                    aEvent.actionPerformed(
                            new ActionEvent(
                                this,
                                eventID,
                                "clicked",
                                time,
                                0));
                    eventID++;
                }
            }
        }
        if( onFocus && enable && visible ) {
            if( InputManager.isKeyDown(InputManager.VK_ENTER) || InputManager.isKeyDown(InputManager.VK_SPACE) ) {
                InputManager.releaseKey(InputManager.VK_ENTER); InputManager.releaseKey(InputManager.VK_SPACE);
                for(int i=0;i<listeners.size();i++) {
                    EventListener tmp = listeners.get(i);
                    if( tmp instanceof ActionListener ) {
                        ActionListener aEvent = (ActionListener)tmp;
                        aEvent.actionPerformed(
                            new ActionEvent(
                                this, eventID, "press",
                                time, 0));
                        eventID++;
                    }
                }
            }
        }
    }

    @Override
    public void render(Graphics g) {
        g.setFont(font);
        if( backgroundColor != null ) {
            g.setColor(enable ? backgroundColor : backgroundColor.darker());
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparence));
            if( roundRect != ROUND_RECT_NONE ) {
                g.fillRoundRect((int)x, (int)y, size.width, size.height,roundRectWidth,roundRectHeight);
            } else {
                g.fillRect((int)x, (int)y, size.width, size.height);
            }
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
            // --
            g.setColor(borderColor);
            if( roundRect == ROUND_RECT_LEFT ) {
                g.drawRect(
                    (int)(x+roundRectWidth/2),
                    (int)y,
                    size.width-roundRectWidth/2, size.height);
            } else if(roundRect == ROUND_RECT_RIGHT ) {
                g.drawRect(
                    (int)x,
                    (int)y,
                    size.width-roundRectWidth/2, size.height);
            } else if(roundRect == ROUND_RECT_TOP ) {
                g.drawRect(
                    (int)x,
                    (int)y+roundRectHeight/2,
                    size.width, size.height-roundRectHeight/2);
            } else if(roundRect == ROUND_RECT_BOTTOM ) {
                g.drawRect(
                    (int)x,
                    (int)y,
                    size.width, size.height-roundRectHeight/2);
            }
            // --
        }
        if( borderColor!=null ) {
            g.setColor(borderColor);
            Stroke s = g.getStroke();
            if( borderSize>0 ) {
                g.setStroke(new BasicStroke(borderSize));
            }
            if( roundRect != ROUND_RECT_NONE ) {
                g.drawRoundRect((int)x, (int)y, size.width, size.height,roundRectWidth,roundRectHeight);
            } else {
                g.drawRect((int)x, (int)y, size.width, size.height);
            }
            g.setStroke(s);
            
            if( roundRect!= ROUND_RECT_NONE ) {
                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparence));
                if( roundRect == ROUND_RECT_LEFT ) {
                    g.setColor(backgroundColor);
                    g.fillRect(
                        (int)(x+roundRectWidth/2),
                        (int)y+1,
                        size.width-roundRectWidth/2, size.height-1);
                } else if(roundRect == ROUND_RECT_RIGHT ) {
                    g.setColor(backgroundColor);
                    g.fillRect(
                        (int)x+1,
                        (int)y+1,
                        size.width-roundRectWidth/2, size.height-1);
                } else if(roundRect == ROUND_RECT_TOP ) {
                    g.setColor(backgroundColor);
                    g.fillRect(
                        (int)x+1,
                        (int)y+roundRectHeight/2,
                        size.width-1, size.height-roundRectHeight/2);
                } else if(roundRect == ROUND_RECT_BOTTOM ) {
                    g.setColor(backgroundColor);
                    g.fillRect(
                        (int)x+1,
                        (int)y+1,
                        size.width-1, size.height-roundRectHeight/2);
                }
                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
            }
        }
        
        float tmpX=x, tmpY=y;
        
        if( icon != null ) {
            tmpX += (float) (size.width/2-icon.getWidth()/2);
            tmpY += icon.getHeight()/2;
            g.draw(icon, (int)tmpX, (int)tmpY);
            tmpX = x;
            tmpY = (float) (y + icon.getHeight()/2);
        }
        
        if( label!= null && !label.isEmpty() ) {
            if( foregroundColor!=null ) {
                g.setColor(foregroundColor);
            }
            else {
                g.setColor(Color.BLACK);
            }
            if( horizontalTextAlign == HORIZONTAL_ALIGN_LEFT ) {
                tmpX+= roundRectWidth/2;
            }
            else if( horizontalTextAlign == HORIZONTAL_ALIGN_CENTER ) {
                tmpX += size.width/2-font.getStringBounds(label, fontContext).getWidth()/2;
            }
            else if(horizontalTextAlign == HORIZONTAL_ALIGN_RIGHT) {
                tmpX += (float)(size.width-font.getStringBounds(label, fontContext).getWidth())-roundRectWidth-3;
            }
            tmpY += (float) (size.height/2 + font.getStringBounds(label, fontContext).getHeight()/2 - 3f);
            g.setFont(font);
            g.drawString(label,(int)tmpX,(int)tmpY);
        }
    }
    
    public void addEventListener(EventListener event) {
        listeners.add(event);
    }
    
    public boolean removeListener(EventListener event) {
        return listeners.remove(event);
    }

    @Override
    public void setHorizontalTextAlign(int horizontalTextAlign) {
        this.horizontalTextAlign = horizontalTextAlign;
    }

    @Override
    public int getHorizontalTextAlign() {
        return horizontalTextAlign;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public Font getFont() {
        return font;
    }

    public void setFont(Font font) {
        this.font = font;
    }

    public Color getForegroundColor() {
        return foregroundColor;
    }

    public void setForegroundColor(Color foregroundColor) {
        this.foregroundColor = foregroundColor;
    }

    public Color getForegroundFocusColor() {
        return foregroundFocusColor;
    }

    public void setForegroundFocusColor(Color foregroundFocusColor) {
        this.foregroundFocusColor = foregroundFocusColor;
    }

    public Texture getIcon() {
        return icon;
    }

    public void setIcon(Texture icon) {
        this.icon = icon;
    }

    public Color getBackgroundColor() {
        return backgroundColor;
    }

    public void setBackgroundColor(Color backgroundColor) {
        this.backgroundColor = backgroundColor;
    }

    public Color getBackgroundFocusColor() {
        return backgroundFocusColor;
    }

    public void setBackgroundFocusColor(Color backgroundFocusColor) {
        this.backgroundFocusColor = backgroundFocusColor;
    }

    public Color getBorderColor() {
        return borderColor;
    }

    public void setBorderColor(Color borderColor) {
        this.borderColor = borderColor;
    }

    public float getBorderSize() {
        return borderSize;
    }

    public void setBorderSize(float borderSize) {
        this.borderSize = borderSize;
    }

    public void setBorder(Color borderColor, float borderSize) {
        setBorderColor(borderColor);
        setBorderSize(borderSize);
    }

    public int getRoundRectWidth() {
        return roundRectWidth;
    }

    public void setRoundRectWidth(int roundRectWidth) {
        this.roundRectWidth = roundRectWidth;
    }

    public int getRoundRectHeight() {
        return roundRectHeight;
    }

    public void setRoundRectHeight(int roundRectHeight) {
        this.roundRectHeight = roundRectHeight;
    }
    
    public void setRoundRectSize(int roundRectWidth, int roundRectHeight) {
        setRoundRectWidth(roundRectWidth);
        setRoundRectHeight(roundRectHeight);
    }

    public float getTransparence() {
        return transparence;
    }

    public void setTransparence(float transparence) {
        this.transparence = transparence;
    }

    public int getRoundRect() {
        return roundRect;
    }

    public void setRoundRect(int roundRect) {
        this.roundRect = roundRect;
    }
    
}
